import {
    request,
    summary,
    body,
    description,
    tagsAll,
    formData,
    responsesAll,
    path,
    query
} from 'koa-swagger-decorator-fork';

import config from 'config'
import fs from 'fs'
import {getFileList,searchFile,setFileName,checkExist,getFilePreview} from '../../utils/nc/file'
import {cleanUrl, parseFilePath} from '../../utils/common'
import responseMapper from '../../utils/responseMapper'
import {FileSchema,FileSearchSchema,RenameFilePathSchema} from '../../schema/index'
import {loadGraphConcept} from "./concept";

const publicPath = config.get('nextcloud.share_path')
const LnkgFormat = 'lnkg'

@tagsAll(['File'])
@responsesAll({
    200: { description: '请求成功' },
    401: {description: 'token认证错误'},
    500: { description: '服务器内部错误(失败原因参考Response body的错误描述)' }
})
export default class FileRouter {

    @request('POST', '/files/attachments')
    @summary('upload attachment')
    @description('上传附件')
    @formData({
        file: {
          type: 'file',
          required: true,
          description: 'upload file, get url'
        },
        name: { type: 'string'},
        path: {type:'string'},
        rewrite: { type: 'boolean'},
        isPublic:{ type:'boolean'}
      })
    static async addAttachment(ctx) {
        let file = ctx.request.files.file,buf,url,sharePath,
            {name,path} = ctx.request.body,
            rewrite = ctx.request.body.rewrite?(ctx.request.body.rewrite=='true'):false,
            isPublic = ctx.request.body.isPublic?(ctx.request.body.isPublic=='true'):false
        buf = fs.readFileSync(file.path)
        name = name||file.name
        path = path||'/'
        sharePath = `/files/${ctx.user.id}${publicPath}${path}`
        if(!rewrite){
            await checkExist(ctx.client,`${sharePath}/${name}`)
        }
        await ctx.client.putFileContents(`${sharePath}/${name}`,buf,{format: "binary",maxContentLength:Infinity })
        url = isPublic?encodeURI(`${ctx.user.shareLink}/download?path=${path}&files=${name}`):encodeURI(`/api/v2/files/${name}?path=${path}`)
        ctx.body = {url}
    }

    @request('POST', '/files')
    @summary('upload graph file')
    @description('上传概念图文件')
    @body(FileSchema)
    static async addGraph(ctx) {
        let {name,data,path} = ctx.request.body,filePath,{filename,format} = parseFilePath(name),url,options,
            rewrite = ctx.request.body.rewrite?(ctx.request.body.rewrite==true||ctx.request.body.rewrite=='true'):false,
            search = ctx.request.body.search?(ctx.request.body.search==true):false,
            versioning = ctx.request.body.versioning?(ctx.request.body.versioning==false||ctx.request.body.versioning=='false'):true,
            isPublic = ctx.request.body.isPublic?(ctx.request.body.isPublic==true ):false,
            prefixPath = ctx.request.body.groupShare?'/':publicPath
            path = path||'/';
        filePath = `/files/${ctx.user.id}${prefixPath}${path}/${name}`
        filePath = cleanUrl(filePath)
        if(!rewrite){
            await checkExist(ctx.client,filePath)
        }
        options = {format:'text',maxContentLength:Infinity}
        if(format==='png'){
            options.format = "binary"
            await ctx.client.putFileContents(filePath,new Buffer(data, 'base64'),options)
        }else{
            console.log("write file length:" + data.length)
            if(!versioning){
                options = {...options,headers:{versioning:false}}
            }
            await ctx.client.putFileContents(filePath,data,options)
            await setFileName(ctx.client,filePath,name)
            if(format==LnkgFormat&&search&&data.mapModels){
                data.title = filename
                await loadGraphConcept(data)
            }
        }
        url = isPublic?encodeURI(`${ctx.user.shareLink}/download?path=${path}&files=${name}`):encodeURI(`/api/v2/files/${name}?path=${path}`)
        ctx.body = {url}
    }

    @request('PUT', '/files/new')
    @summary('create folder')
    @description('创建目录')
    @body(FileSchema)
    static async addFolder(ctx) {
        let {path,name} = ctx.request.body,sharePath = `/files/${ctx.user.id}${publicPath}`
        path = path ||'/'
        await ctx.client.createDirectory(`${sharePath}${path}/${name}`)
        ctx.body = {}
    }

    @request('GET', '/files')
    @summary('list file')
    @query({
        path:{type:'string'},
        showHidden:{type:'boolean'},
        treeMode:{type:'boolean'},
        pattern:{type:'string',example:'*.lnkg'},
        excludes:{type:'string'},
        groupShare:{type:'boolean'}
    })
    @description('查询文件列表')
    static async findFiles(ctx) {
        let groupShare = ctx.query.groupShare=='true'?true:false,
            prefixPath = groupShare?'/':publicPath,
            shareFolder = `/files/${ctx.user.id}${prefixPath}`,
            showHidden = ctx.query.showHidden=='true'?true:false,
            treeMode = ctx.query.treeMode=='true'?true:false,
            path = ctx.query.path||'/',pattern = ctx.query.pattern?.split(','),excludes = ctx.query.excludes?.split(',')
        let files = await getFileList(ctx.client,ctx.user,`${shareFolder}${path}`,showHidden,groupShare,pattern,excludes);
        let result = responseMapper.wrapResponse(ctx,files,path,treeMode)
        ctx.body = result
    }

    @request('GET', '/files/{name}')
    @summary('get file content by name')
    @description('查询指定文件内容')
    @path({ name: { type: 'string', required: true } },{ path: { type: 'string'} })
    @query({
        path: { type: 'string'},
        groupShare:{type: 'boolean'}
    })
    static async getFileContent(ctx) {
        let prefixPath = ctx.query.groupShare?'/':publicPath,content,
            sharePath = `/files/${ctx.user.id}${prefixPath}`,{name} = ctx.params,{path} = ctx.query;
        path = path || '/'
        try {
            content = await ctx.client.getFileContents(cleanUrl(`${sharePath}${path}/${name}`));
        }catch(err){
            content = {error:err.message}
        }
        ctx.body = content
    }

    @request('DELETE', '/files/{name}')
    @summary('delete file by name')
    @description('删除文件')
    @path({ name: { type: 'string', required: true } })
    @query({
        path: { type: 'string'}
    })
    static async delFile(ctx) {
        let sharePath = `/files/${ctx.user.id}${publicPath}`,path = ctx.query.path
        path = path || '/'
        await ctx.client.deleteFile(`${sharePath}${path}/${ctx.params.name}`)
        ctx.body = {}
    }

    @request('PUT', '/files')
    @summary('rename file')
    @description('重命名文件')
    @body(RenameFilePathSchema)
    static async renameFile(ctx) {
        let sharePath = `/files/${ctx.user.id}${publicPath}`,{srcFile,dstFile} = ctx.request.body
        await ctx.client.moveFile(`${sharePath}${srcFile}`,`${sharePath}${dstFile}`)
        ctx.body = {}
    }

    @request('POST', '/files/search')
    @summary('search file by name')
    @body(FileSearchSchema)
    @description('搜索文件')
    static async searchFile(ctx) {
        let treeMode = ((ctx.request.body.treeMode===true)?true:false)
        let files = await searchFile(ctx.client,ctx.user,ctx.request.body)
        let result = responseMapper.wrapResponse(ctx,files,ctx.request.body.path||'/',treeMode)
        ctx.body = result
    }

    @request('GET', '/files/preview/{fileId}')
    @summary('preview file by id')
    @description('预览文件内容')
    @path({ fileId: { type: 'string', required: true } })
    @query({
        x: { type: 'number'},
        y:{type: 'number'}
    })
    static async previewFileContent(ctx) {
        let content,x = ctx.query.x ||40,y = ctx.query.y ||30
        try {
            content = await getFilePreview(ctx.user,ctx.params.fileId,x,y)
            ctx.type = 'image/png'
        }catch(err){
            content = {error:err.message}
        }
        ctx.body = content
    }
}
